library(Seurat)
library(DAAG)
library(tidyverse)
library(relaimpo)
library(bootstrap)

Read in tumor object

subset tumor seurat obeject to TN only

tn_samples <- filter(tiss_subset_tumor2@meta.data, sample_name == "LT_S34" | sample_name == "LT_S43" | sample_name == "LT_S45" | sample_name == "LT_S49" | sample_name == "LT_S52" | sample_name == "LT_S51" | sample_name == "LT_S56" | sample_name == "LT_S67" | sample_name == "LT_S69" | sample_name == "LT_S74" | sample_name == "LT_S75")
tn_seurat <- SubsetData(tiss_subset_tumor2, cells.use = tn_samples$cell_id)
rownames(tn_seurat@meta.data) <- tn_seurat@meta.data$cell_id

Investigate each Signature found from grouped analysis: 1. Alveolar Sig 2. Kynurenine Sig 3. Plasminogen Sig 4. Serpine1 5. Gap Junction Sig

  1. Alveolar Sig
DOR_Alveolar <- as.data.frame(FetchData(object = tn_seurat, vars.all = c("SFTPC", "SFTPB", "SFTPD", "PGC", "CLDN18", "AQP4", "SCGB3A1", "ABCA3", "GATA6", "NKX2-1", "SFTA3", "IGFBP2", "HOPX", "NAPSA", "FOXA2", "AGER", "LAMP1")))
DOR_Alveolar$cell_id <- rownames(DOR_Alveolar)
DOR_Alveolar <- merge(tn_seurat@meta.data, DOR_Alveolar, by = "cell_id")
rownames(DOR_Alveolar) <- DOR_Alveolar$cell_id
  1. Kynurenine Sig
DOR_Kynurenine <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('IDO1', 'KYNU', 'QPRT')))
DOR_Kynurenine$cell_id <- rownames(DOR_Kynurenine)
DOR_Kynurenine <- merge(tn_seurat@meta.data, DOR_Kynurenine, by = "cell_id")
rownames(DOR_Kynurenine) <- DOR_Kynurenine$cell_id
  1. Plasminogen Sig
DOR_Plasminogen <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('ANXA2', 'PLAT', 'PLAU', 'PLAUR')))
DOR_Plasminogen$cell_id <- rownames(DOR_Plasminogen)
DOR_Plasminogen <- merge(tn_seurat@meta.data, DOR_Plasminogen, by = "cell_id")
rownames(DOR_Plasminogen) <- DOR_Plasminogen$cell_id
  1. Serpine1
DOR_SERPINE1 <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('SERPINE1')))
DOR_SERPINE1$cell_id <- rownames(DOR_SERPINE1)
DOR_SERPINE1 <- merge(tn_seurat@meta.data, DOR_SERPINE1, by = "cell_id")
rownames(DOR_SERPINE1) <- DOR_SERPINE1$cell_id
  1. Gap Junction Sig
DOR_GapJunction <- as.data.frame(FetchData(object = tn_seurat, vars.all = c('GJB3', 'GJB2', 'GJB4','GJB5')))
DOR_GapJunction$cell_id <- rownames(DOR_GapJunction)
DOR_GapJunction <- merge(tn_seurat@meta.data, DOR_GapJunction, by = "cell_id")
rownames(DOR_GapJunction) <- DOR_GapJunction$cell_id

fit 1 = Alveolar Sig

summary(fit1) # show results

Call:
lm(formula = dor ~ SFTPC + SFTPB + SFTPD + PGC + CLDN18 + AQP4 + 
    SCGB3A1 + ABCA3 + GATA6 + `NKX2-1` + SFTA3 + IGFBP2 + HOPX + 
    NAPSA + FOXA2 + AGER + LAMP1, data = DOR_Alveolar)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.31790 -0.03572  0.00897  0.04640  0.19908 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.6616254  0.0056816 116.451  < 2e-16 ***
SFTPC        0.0116742  0.0063559   1.837 0.066646 .  
SFTPB        0.0022941  0.0025315   0.906 0.365098    
SFTPD       -0.0429224  0.0107056  -4.009  6.7e-05 ***
PGC         -0.0082526  0.0135026  -0.611 0.541261    
CLDN18       0.0007957  0.0196329   0.041 0.967680    
AQP4        -0.0040422  0.0107509  -0.376 0.707031    
SCGB3A1     -0.0011107  0.0060576  -0.183 0.854568    
ABCA3       -0.0034290  0.0096255  -0.356 0.721763    
GATA6       -0.0226240  0.0228514  -0.990 0.322471    
`NKX2-1`    -0.0451323  0.0044903 -10.051  < 2e-16 ***
SFTA3        0.0054035  0.0059639   0.906 0.365205    
IGFBP2       0.0330716  0.0016918  19.548  < 2e-16 ***
HOPX        -0.0335134  0.0036519  -9.177  < 2e-16 ***
NAPSA       -0.0302077  0.0033578  -8.996  < 2e-16 ***
FOXA2       -0.0273386  0.0044887  -6.091  1.8e-09 ***
AGER        -0.0907966  0.0243912  -3.723 0.000212 ***
LAMP1        0.0030322  0.0095368   0.318 0.750610    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.071 on 745 degrees of freedom
Multiple R-squared:  0.7277,    Adjusted R-squared:  0.7214 
F-statistic: 117.1 on 17 and 745 DF,  p-value: < 2.2e-16

fit2 = Kynurenine Sig

fit2 <- lm(dor ~ IDO1 + KYNU + QPRT, data=DOR_Kynurenine)
summary(fit2) # show results

Call:
lm(formula = dor ~ IDO1 + KYNU + QPRT, data = DOR_Kynurenine)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.35619 -0.09619 -0.09157  0.15381  0.25432 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.656187   0.005075 129.289  < 2e-16 ***
IDO1        -0.025909   0.013803  -1.877  0.06089 .  
KYNU         0.026314   0.009387   2.803  0.00519 ** 
QPRT        -0.103465   0.015602  -6.631 6.31e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1303 on 759 degrees of freedom
Multiple R-squared:  0.0659,    Adjusted R-squared:  0.0622 
F-statistic: 17.85 on 3 and 759 DF,  p-value: 3.348e-11
# diagnostic plots 
plot(fit2)

ggplot(DOR_Kynurenine, aes(x = IDO1, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Kynurenine, aes(x = KYNU, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Kynurenine, aes(x = QPRT, y = dor, color = sample_name)) + geom_point()

fit3 = Plasminogen Sig

fit3 <- lm(dor ~ PLAU + PLAUR + PLAT + ANXA2, data=DOR_Plasminogen)
summary(fit3) # show results

Call:
lm(formula = dor ~ PLAU + PLAUR + PLAT + ANXA2, data = DOR_Plasminogen)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.39284 -0.07108  0.02876  0.07998  0.24803 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.515175   0.013690  37.631  < 2e-16 ***
PLAU        -0.026385   0.004716  -5.595 3.08e-08 ***
PLAUR       -0.031850   0.006093  -5.227 2.22e-07 ***
PLAT        -0.043839   0.003904 -11.229  < 2e-16 ***
ANXA2        0.056471   0.003923  14.393  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1065 on 758 degrees of freedom
Multiple R-squared:  0.3766,    Adjusted R-squared:  0.3733 
F-statistic: 114.5 on 4 and 758 DF,  p-value: < 2.2e-16
# diagnostic plots 
plot(fit3)

ggplot(DOR_Plasminogen, aes(x = PLAU, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Plasminogen, aes(x = PLAUR, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Plasminogen, aes(x = PLAT, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_Plasminogen, aes(x = ANXA2, y = dor, color = sample_name)) + geom_point()

fit4 = SERPINE1

fit4 <- lm(dor ~ SERPINE1, data=DOR_SERPINE1)
summary(fit4) # show results

Call:
lm(formula = dor ~ SERPINE1, data = DOR_SERPINE1)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.36405 -0.10405 -0.04199  0.14595  0.25223 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.664046   0.005113 129.880  < 2e-16 ***
SERPINE1    -0.047593   0.007384  -6.446 2.04e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1311 on 761 degrees of freedom
Multiple R-squared:  0.05177,   Adjusted R-squared:  0.05052 
F-statistic: 41.55 on 1 and 761 DF,  p-value: 2.042e-10
# diagnostic plots 
plot(fit4)

ggplot(DOR_SERPINE1, aes(x = SERPINE1, y = dor, color = sample_name)) + geom_point()

fit5 = Gap Junction Sig

fit5 <- lm(dor ~ GJB3 + GJB2 + GJB4 + GJB5, data=DOR_GapJunction)
summary(fit5) # show results

Call:
lm(formula = dor ~ GJB3 + GJB2 + GJB4 + GJB5, data = DOR_GapJunction)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.33107 -0.07003 -0.07003  0.14248  0.17997 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 0.630034   0.004815 130.836  < 2e-16 ***
GJB3        0.029685   0.018856   1.574   0.1158    
GJB2        0.042758   0.023258   1.838   0.0664 .  
GJB4        0.102237   0.016175   6.321 4.44e-10 ***
GJB5        0.124777   0.014473   8.622  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1227 on 758 degrees of freedom
Multiple R-squared:  0.1722,    Adjusted R-squared:  0.1678 
F-statistic: 39.42 on 4 and 758 DF,  p-value: < 2.2e-16
# diagnostic plots 
plot(fit5)

ggplot(DOR_GapJunction, aes(x = GJB2, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_GapJunction, aes(x = GJB3, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_GapJunction, aes(x = GJB4, y = dor, color = sample_name)) + geom_point()

ggplot(DOR_GapJunction, aes(x = GJB5, y = dor, color = sample_name)) + geom_point()

# # K-fold cross-validation
# cv.lm(data = DOR_GapJunction, form.lm = fit5, m = 10, plotit = FALSE)
# # Assessing R2 shrinkage using 10-Fold Cross-Validation 
# # define functions 
# theta.fit <- function(x,y){lsfit(x,y)}
# theta.predict <- function(fit5,x){cbind(1,x)%*%fit5$coef} 
# 
# # matrix of predictors
# X <- as.matrix(DOR_GapJunction[c("GJB3","GJB2","GJB4","GJB5")])
# # vector of predicted values
# y <- as.matrix(DOR_GapJunction[c("dor")]) 
# 
# results <- crossval(X,y,theta.fit,theta.predict,ngroup=10)
# cor(y, fit5$fitted.values)**2 # raw R2 
# cor(y,results$cv.fit5)**2 # cross-validated R2
# 
# # Calculate Relative Importance for Each Predictor
# calc.relimp(fit5,type = c("lmg","last","first","pratt"), rela=TRUE)
# # Bootstrap Measures of Relative Importance (1000 samples) 
# boot <- boot.relimp(fit5, b = 1000, type = c("lmg", "last", "first", "pratt"), rank = TRUE, diff = TRUE, rela = TRUE)
# booteval.relimp(boot) # print result
# plot(booteval.relimp(boot,sort=TRUE)) # plot result
table(tn_seurat@meta.data$biopsy_site, tn_seurat@meta.data$dor)
         
          0.3 0.31 0.43 0.46 0.5 0.56 0.57 0.7 0.81
  Adrenal   0    1    0    0   0    0    0   0    0
  Brain     0    0    0    0   0    0    0   0    0
  Liver     0    0    0    0   0    0    0  28    0
  LN        0    0    5    0   6  305   16   0    0
  Lung     14    0    0    0   0   71    0   0  293
  Pleura    0    0    0   24   0    0    0   0    0
table(tn_seurat@meta.data$sample_name, tn_seurat@meta.data$dor)
        
         0.3 0.31 0.43 0.46 0.5 0.56 0.57 0.7 0.81
  LT_S34   0    0    0   24   0    0    0   0    0
  LT_S43   0    0    5    0   0    0    0   0    0
  LT_S45   0    1    0    0   0    0    0   0    0
  LT_S49   0    0    0    0   6    0    0   0    0
  LT_S51   0    0    0    0   0    0   16   0    0
  LT_S52  14    0    0    0   0    0    0   0    0
  LT_S56   0    0    0    0   0    0    0   0  291
  LT_S67   0    0    0    0   0    0    0   0    2
  LT_S69   0    0    0    0   0  305    0   0    0
  LT_S74   0    0    0    0   0   71    0   0    0
  LT_S75   0    0    0    0   0    0    0  28    0
table(tn_seurat@meta.data$sample_name)

LT_S34 LT_S43 LT_S45 LT_S49 LT_S51 LT_S52 LT_S56 LT_S67 LT_S69 LT_S74 LT_S75 
    24      5      1      6     16     14    291      2    305     71     28 

Bulkize the samples

tn_seurat <- SetIdent(tn_seurat, ident.use = tn_seurat@meta.data$sample_name)
table(tn_seurat@ident)

LT_S34 LT_S43 LT_S45 LT_S49 LT_S51 LT_S52 LT_S56 LT_S67 LT_S69 LT_S74 LT_S75 
    24      5      1      6     16     14    291      2    305     71     28 
sample.averages <- AverageExpression(object = tn_seurat)
Finished averaging RNA for cluster LT_S34
Finished averaging RNA for cluster LT_S43
Finished averaging RNA for cluster LT_S45
Finished averaging RNA for cluster LT_S49
Finished averaging RNA for cluster LT_S51
Finished averaging RNA for cluster LT_S52
Finished averaging RNA for cluster LT_S56
Finished averaging RNA for cluster LT_S67
Finished averaging RNA for cluster LT_S69
Finished averaging RNA for cluster LT_S74
Finished averaging RNA for cluster LT_S75

To find DE genes between bulkized TN samples with low and high DOR, export table with groups

# set up table 
sample.averages.t <- as.data.frame(t(sample.averages))
head(sample.averages.t)
sample.averages.t$sample_name <- rownames(sample.averages.t)
sample.averages.t <- left_join(sample.averages.t, dor_meta, by = "sample_name")
rownames(sample.averages.t) <- sample.averages.t$sample_name
length(colnames(sample.averages.t))
[1] 26489
DE_avg <- pairwise.wilcox.test(x = sample.averages.t$EGFR, g = sample.averages.t$dor_class)
write.csv(sample.averages.t, file = "/myVolume/TN_bulkized_data.csv")
TN.sample.averages <- sample.averages
head(TN.sample.averages)

Bulkize fit analysis Alveolar

Bulkize fit analysis Kynurenine

Bulkize fit analysis Plasminogen

Bulkize fit analysis of SERPINE1

Bulkize fit analysis GapJunction

bulkized_TN_markers <- read.csv(file = paste(dir, "Data_input/mwu_luad.csv", sep = ""))
bulkized_TN_markers.f <- filter(bulkized_TN_markers, pval_1 <= 0.05)
hist(bulkized_TN_markers.f$stat_1)

length(bulkized_TN_markers.f$pval_1)
[1] 4115
bulkized_TN_markers.f <- bulkized_TN_markers.f[order(bulkized_TN_markers.f$stat_1, decreasing = FALSE), ] 

Most compelling high expression corr to low dor

ggplot(sample.averages.t, aes(x = ADAR, y = dor)) + geom_point(aes(color = patient_id))

ggplot(sample.averages.t, aes(x = CFL1, y = dor)) + geom_point(aes(color = patient_id))

Most compelling high expression corr to high dor

ggplot(sample.averages.t, aes(x = TTLL13P, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = ALS2, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = RLN1, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = USP45, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = BDKRB1, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = LINC01061, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = ZNF563, y = dor)) + geom_point(aes(color = dor_class))

ggplot(sample.averages.t, aes(x = WDR19, y = dor)) + geom_point(aes(color = dor_class))

LS0tCnRpdGxlOiAiUmVncmVzc2lvbiBvZiBDbGluaWNhbCBPdXRjb21lcyB0byBTaWdzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoREFBRykKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmVsYWltcG8pCmxpYnJhcnkoYm9vdHN0cmFwKQpgYGAKClJlYWQgaW4gdHVtb3Igb2JqZWN0CmBgYHtyfQojIHJtKGxpc3Q9bHMoKSkKZGlyIDwtICIvbXlWb2x1bWUvc2NlbGxfbHVuZ19hZGVub2NhcmNpbm9tYS8iCmxvYWQoZmlsZSA9IHBhc3RlKGRpciwgIkRhdGFfaW5wdXQvb2JqZWN0cy9OSTA0X3R1bW9yX3NldXJhdF9vYmplY3QuUkRhdGEiLCBzZXAgPSAiIikpCgojUmVhZCBpbiBkZXB0aCBvZiByZXNwb25zZSBjbGluaWNhbCBvdXRjb21lcwpkb3JfbWV0YSA8LSByZWFkLmNzdihmaWxlID0gcGFzdGUoZGlyLCAiRGF0YV9pbnB1dC9jc3ZfZmlsZXMvZGVwdGhvZnJlc3BvbnNlX3RuLmNzdiIsIHNlcCA9ICIiKSkKI2NvcnJlY3QgbWlzYW5ub2F0aW9uIGluIGRvcgpkb3JfbWV0YSRzYW1wbGVfbmFtZSA8LSBnc3ViKHBhdHRlcm4gPSAiTFRfUzU3IiwgcmVwbGFjZW1lbnQgPSAiTFRfUzUxIiwgeCA9IGRvcl9tZXRhJHNhbXBsZV9uYW1lKQpkb3JfbWV0YSRkb3IgPC0gZ3N1YihwYXR0ZXJuID0gIi4xMiIsIHJlcGxhY2VtZW50ID0gIi40NiIsIHggPSBkb3JfbWV0YSRkb3IpCmRvcl9tZXRhJGRvcl9jbGFzcyA8LSBjKCJsb3ciLCAibG93IiwgImxvdyIsICJsb3ciLCAibG93IiwgImhpZ2giLCAiaGlnaCIsICJoaWdoIiwgImhpZ2giLCAiaGlnaCIsICJoaWdoIikKZG9yX21ldGEKYGBgCgpzdWJzZXQgdHVtb3Igc2V1cmF0IG9iZWplY3QgdG8gVE4gb25seQpgYGB7cn0KdG5fc2FtcGxlcyA8LSBmaWx0ZXIodGlzc19zdWJzZXRfdHVtb3IyQG1ldGEuZGF0YSwgc2FtcGxlX25hbWUgPT0gIkxUX1MzNCIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzQzIiB8IHNhbXBsZV9uYW1lID09ICJMVF9TNDUiIHwgc2FtcGxlX25hbWUgPT0gIkxUX1M0OSIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzUyIiB8IHNhbXBsZV9uYW1lID09ICJMVF9TNTEiIHwgc2FtcGxlX25hbWUgPT0gIkxUX1M1NiIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzY3IiB8IHNhbXBsZV9uYW1lID09ICJMVF9TNjkiIHwgc2FtcGxlX25hbWUgPT0gIkxUX1M3NCIgfCBzYW1wbGVfbmFtZSA9PSAiTFRfUzc1IikKCnRuX3NldXJhdCA8LSBTdWJzZXREYXRhKHRpc3Nfc3Vic2V0X3R1bW9yMiwgY2VsbHMudXNlID0gdG5fc2FtcGxlcyRjZWxsX2lkKQpyb3duYW1lcyh0bl9zZXVyYXRAbWV0YS5kYXRhKSA8LSB0bl9zZXVyYXRAbWV0YS5kYXRhJGNlbGxfaWQKYGBgCgoKYGBge3J9CnRuX3NldXJhdEBtZXRhLmRhdGEgPC0gbWVyZ2UoZG9yX21ldGFbLGMoMjo0KV0sIHRuX3NldXJhdEBtZXRhLmRhdGEsIGJ5ID0gInNhbXBsZV9uYW1lIikKcm93bmFtZXModG5fc2V1cmF0QG1ldGEuZGF0YSkgPC0gdG5fc2V1cmF0QG1ldGEuZGF0YSRjZWxsX2lkCmBgYAoKCkludmVzdGlnYXRlIGVhY2ggU2lnbmF0dXJlIGZvdW5kIGZyb20gZ3JvdXBlZCBhbmFseXNpczoKMS4gQWx2ZW9sYXIgU2lnCjIuIEt5bnVyZW5pbmUgU2lnCjMuIFBsYXNtaW5vZ2VuIFNpZwo0LiBTZXJwaW5lMQo1LiBHYXAgSnVuY3Rpb24gU2lnCgoxLiBBbHZlb2xhciBTaWcKYGBge3J9CkRPUl9BbHZlb2xhciA8LSBhcy5kYXRhLmZyYW1lKEZldGNoRGF0YShvYmplY3QgPSB0bl9zZXVyYXQsIHZhcnMuYWxsID0gYygiU0ZUUEMiLCAiU0ZUUEIiLCAiU0ZUUEQiLCAiUEdDIiwgIkNMRE4xOCIsICJBUVA0IiwgIlNDR0IzQTEiLCAiQUJDQTMiLCAiR0FUQTYiLCAiTktYMi0xIiwgIlNGVEEzIiwgIklHRkJQMiIsICJIT1BYIiwgIk5BUFNBIiwgIkZPWEEyIiwgIkFHRVIiLCAiTEFNUDEiKSkpCkRPUl9BbHZlb2xhciRjZWxsX2lkIDwtIHJvd25hbWVzKERPUl9BbHZlb2xhcikKRE9SX0FsdmVvbGFyIDwtIG1lcmdlKHRuX3NldXJhdEBtZXRhLmRhdGEsIERPUl9BbHZlb2xhciwgYnkgPSAiY2VsbF9pZCIpCnJvd25hbWVzKERPUl9BbHZlb2xhcikgPC0gRE9SX0FsdmVvbGFyJGNlbGxfaWQKYGBgCgoyLiBLeW51cmVuaW5lIFNpZwpgYGB7cn0KRE9SX0t5bnVyZW5pbmUgPC0gYXMuZGF0YS5mcmFtZShGZXRjaERhdGEob2JqZWN0ID0gdG5fc2V1cmF0LCB2YXJzLmFsbCA9IGMoJ0lETzEnLCAnS1lOVScsICdRUFJUJykpKQpET1JfS3ludXJlbmluZSRjZWxsX2lkIDwtIHJvd25hbWVzKERPUl9LeW51cmVuaW5lKQpET1JfS3ludXJlbmluZSA8LSBtZXJnZSh0bl9zZXVyYXRAbWV0YS5kYXRhLCBET1JfS3ludXJlbmluZSwgYnkgPSAiY2VsbF9pZCIpCnJvd25hbWVzKERPUl9LeW51cmVuaW5lKSA8LSBET1JfS3ludXJlbmluZSRjZWxsX2lkCmBgYAoKMy4gUGxhc21pbm9nZW4gU2lnCmBgYHtyfQpET1JfUGxhc21pbm9nZW4gPC0gYXMuZGF0YS5mcmFtZShGZXRjaERhdGEob2JqZWN0ID0gdG5fc2V1cmF0LCB2YXJzLmFsbCA9IGMoJ0FOWEEyJywgJ1BMQVQnLCAnUExBVScsICdQTEFVUicpKSkKRE9SX1BsYXNtaW5vZ2VuJGNlbGxfaWQgPC0gcm93bmFtZXMoRE9SX1BsYXNtaW5vZ2VuKQpET1JfUGxhc21pbm9nZW4gPC0gbWVyZ2UodG5fc2V1cmF0QG1ldGEuZGF0YSwgRE9SX1BsYXNtaW5vZ2VuLCBieSA9ICJjZWxsX2lkIikKcm93bmFtZXMoRE9SX1BsYXNtaW5vZ2VuKSA8LSBET1JfUGxhc21pbm9nZW4kY2VsbF9pZApgYGAKCjQuIFNlcnBpbmUxCmBgYHtyfQpET1JfU0VSUElORTEgPC0gYXMuZGF0YS5mcmFtZShGZXRjaERhdGEob2JqZWN0ID0gdG5fc2V1cmF0LCB2YXJzLmFsbCA9IGMoJ1NFUlBJTkUxJykpKQpET1JfU0VSUElORTEkY2VsbF9pZCA8LSByb3duYW1lcyhET1JfU0VSUElORTEpCkRPUl9TRVJQSU5FMSA8LSBtZXJnZSh0bl9zZXVyYXRAbWV0YS5kYXRhLCBET1JfU0VSUElORTEsIGJ5ID0gImNlbGxfaWQiKQpyb3duYW1lcyhET1JfU0VSUElORTEpIDwtIERPUl9TRVJQSU5FMSRjZWxsX2lkCmBgYAoKNS4gR2FwIEp1bmN0aW9uIFNpZwpgYGB7cn0KRE9SX0dhcEp1bmN0aW9uIDwtIGFzLmRhdGEuZnJhbWUoRmV0Y2hEYXRhKG9iamVjdCA9IHRuX3NldXJhdCwgdmFycy5hbGwgPSBjKCdHSkIzJywgJ0dKQjInLCAnR0pCNCcsJ0dKQjUnKSkpCkRPUl9HYXBKdW5jdGlvbiRjZWxsX2lkIDwtIHJvd25hbWVzKERPUl9HYXBKdW5jdGlvbikKRE9SX0dhcEp1bmN0aW9uIDwtIG1lcmdlKHRuX3NldXJhdEBtZXRhLmRhdGEsIERPUl9HYXBKdW5jdGlvbiwgYnkgPSAiY2VsbF9pZCIpCnJvd25hbWVzKERPUl9HYXBKdW5jdGlvbikgPC0gRE9SX0dhcEp1bmN0aW9uJGNlbGxfaWQKYGBgCgpmaXQgMSA9IEFsdmVvbGFyIFNpZwpgYGB7cn0KZml0MSA8LSBsbShkb3IgfiBTRlRQQyArU0ZUUEIgKyBTRlRQRCArIFBHQyArIENMRE4xOCArIEFRUDQgKyBTQ0dCM0ExICsgQUJDQTMgKyBHQVRBNiArIGBOS1gyLTFgICsgU0ZUQTMgKyBJR0ZCUDIrIEhPUFggKyBOQVBTQSArIEZPWEEyICsgQUdFUiArIExBTVAxLCBkYXRhPURPUl9BbHZlb2xhcikKc3VtbWFyeShmaXQxKSAjIHNob3cgcmVzdWx0cwoKIyBkaWFnbm9zdGljIHBsb3RzCnBsb3QoZml0MSkKCmdncGxvdChET1JfQWx2ZW9sYXIsIGFlcyh4ID0gYE5LWDItMWAsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX0FsdmVvbGFyLCBhZXMoeCA9IElHRkJQMiwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfQWx2ZW9sYXIsIGFlcyh4ID0gSE9QWCwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfQWx2ZW9sYXIsIGFlcyh4ID0gTkFQU0EsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX0FsdmVvbGFyLCBhZXMoeCA9IEZPWEEyLCB5ID0gZG9yLCBjb2xvciA9IHNhbXBsZV9uYW1lKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpmaXQyID0gS3ludXJlbmluZSBTaWcKYGBge3J9CmZpdDIgPC0gbG0oZG9yIH4gSURPMSArIEtZTlUgKyBRUFJULCBkYXRhPURPUl9LeW51cmVuaW5lKQpzdW1tYXJ5KGZpdDIpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0MikKCmdncGxvdChET1JfS3ludXJlbmluZSwgYWVzKHggPSBJRE8xLCB5ID0gZG9yLCBjb2xvciA9IHNhbXBsZV9uYW1lKSkgKyBnZW9tX3BvaW50KCkKZ2dwbG90KERPUl9LeW51cmVuaW5lLCBhZXMoeCA9IEtZTlUsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX0t5bnVyZW5pbmUsIGFlcyh4ID0gUVBSVCwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmBgYAoKZml0MyA9IFBsYXNtaW5vZ2VuIFNpZwpgYGB7cn0KZml0MyA8LSBsbShkb3IgfiBQTEFVICsgUExBVVIgKyBQTEFUICsgQU5YQTIsIGRhdGE9RE9SX1BsYXNtaW5vZ2VuKQpzdW1tYXJ5KGZpdDMpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0MykKCmdncGxvdChET1JfUGxhc21pbm9nZW4sIGFlcyh4ID0gUExBVSwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfUGxhc21pbm9nZW4sIGFlcyh4ID0gUExBVVIsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX1BsYXNtaW5vZ2VuLCBhZXMoeCA9IFBMQVQsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoRE9SX1BsYXNtaW5vZ2VuLCBhZXMoeCA9IEFOWEEyLCB5ID0gZG9yLCBjb2xvciA9IHNhbXBsZV9uYW1lKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpmaXQ0ID0gU0VSUElORTEKYGBge3J9CmZpdDQgPC0gbG0oZG9yIH4gU0VSUElORTEsIGRhdGE9RE9SX1NFUlBJTkUxKQpzdW1tYXJ5KGZpdDQpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0NCkKCmdncGxvdChET1JfU0VSUElORTEsIGFlcyh4ID0gU0VSUElORTEsIHkgPSBkb3IsIGNvbG9yID0gc2FtcGxlX25hbWUpKSArIGdlb21fcG9pbnQoKQpgYGAKCmZpdDUgPSBHYXAgSnVuY3Rpb24gU2lnCmBgYHtyfQpmaXQ1IDwtIGxtKGRvciB+IEdKQjMgKyBHSkIyICsgR0pCNCArIEdKQjUsIGRhdGE9RE9SX0dhcEp1bmN0aW9uKQpzdW1tYXJ5KGZpdDUpICMgc2hvdyByZXN1bHRzCgojIGRpYWdub3N0aWMgcGxvdHMgCnBsb3QoZml0NSkKCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCMiwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCMywgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCNCwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCmdncGxvdChET1JfR2FwSnVuY3Rpb24sIGFlcyh4ID0gR0pCNSwgeSA9IGRvciwgY29sb3IgPSBzYW1wbGVfbmFtZSkpICsgZ2VvbV9wb2ludCgpCgojICMgSy1mb2xkIGNyb3NzLXZhbGlkYXRpb24KIyBjdi5sbShkYXRhID0gRE9SX0dhcEp1bmN0aW9uLCBmb3JtLmxtID0gZml0NSwgbSA9IDEwLCBwbG90aXQgPSBGQUxTRSkKIyAjIEFzc2Vzc2luZyBSMiBzaHJpbmthZ2UgdXNpbmcgMTAtRm9sZCBDcm9zcy1WYWxpZGF0aW9uIAojICMgZGVmaW5lIGZ1bmN0aW9ucyAKIyB0aGV0YS5maXQgPC0gZnVuY3Rpb24oeCx5KXtsc2ZpdCh4LHkpfQojIHRoZXRhLnByZWRpY3QgPC0gZnVuY3Rpb24oZml0NSx4KXtjYmluZCgxLHgpJSolZml0NSRjb2VmfSAKIyAKIyAjIG1hdHJpeCBvZiBwcmVkaWN0b3JzCiMgWCA8LSBhcy5tYXRyaXgoRE9SX0dhcEp1bmN0aW9uW2MoIkdKQjMiLCJHSkIyIiwiR0pCNCIsIkdKQjUiKV0pCiMgIyB2ZWN0b3Igb2YgcHJlZGljdGVkIHZhbHVlcwojIHkgPC0gYXMubWF0cml4KERPUl9HYXBKdW5jdGlvbltjKCJkb3IiKV0pIAojIAojIHJlc3VsdHMgPC0gY3Jvc3N2YWwoWCx5LHRoZXRhLmZpdCx0aGV0YS5wcmVkaWN0LG5ncm91cD0xMCkKIyBjb3IoeSwgZml0NSRmaXR0ZWQudmFsdWVzKSoqMiAjIHJhdyBSMiAKIyBjb3IoeSxyZXN1bHRzJGN2LmZpdDUpKioyICMgY3Jvc3MtdmFsaWRhdGVkIFIyCiMgCiMgIyBDYWxjdWxhdGUgUmVsYXRpdmUgSW1wb3J0YW5jZSBmb3IgRWFjaCBQcmVkaWN0b3IKIyBjYWxjLnJlbGltcChmaXQ1LHR5cGUgPSBjKCJsbWciLCJsYXN0IiwiZmlyc3QiLCJwcmF0dCIpLCByZWxhPVRSVUUpCiMgIyBCb290c3RyYXAgTWVhc3VyZXMgb2YgUmVsYXRpdmUgSW1wb3J0YW5jZSAoMTAwMCBzYW1wbGVzKSAKIyBib290IDwtIGJvb3QucmVsaW1wKGZpdDUsIGIgPSAxMDAwLCB0eXBlID0gYygibG1nIiwgImxhc3QiLCAiZmlyc3QiLCAicHJhdHQiKSwgcmFuayA9IFRSVUUsIGRpZmYgPSBUUlVFLCByZWxhID0gVFJVRSkKIyBib290ZXZhbC5yZWxpbXAoYm9vdCkgIyBwcmludCByZXN1bHQKIyBwbG90KGJvb3RldmFsLnJlbGltcChib290LHNvcnQ9VFJVRSkpICMgcGxvdCByZXN1bHQKYGBgCgpgYGB7cn0KdGFibGUodG5fc2V1cmF0QG1ldGEuZGF0YSRiaW9wc3lfc2l0ZSwgdG5fc2V1cmF0QG1ldGEuZGF0YSRkb3IpCnRhYmxlKHRuX3NldXJhdEBtZXRhLmRhdGEkc2FtcGxlX25hbWUsIHRuX3NldXJhdEBtZXRhLmRhdGEkZG9yKQp0YWJsZSh0bl9zZXVyYXRAbWV0YS5kYXRhJHNhbXBsZV9uYW1lKQpgYGAKCkJ1bGtpemUgdGhlIHNhbXBsZXMKYGBge3J9CnRuX3NldXJhdCA8LSBTZXRJZGVudCh0bl9zZXVyYXQsIGlkZW50LnVzZSA9IHRuX3NldXJhdEBtZXRhLmRhdGEkc2FtcGxlX25hbWUpCnRhYmxlKHRuX3NldXJhdEBpZGVudCkKc2FtcGxlLmF2ZXJhZ2VzIDwtIEF2ZXJhZ2VFeHByZXNzaW9uKG9iamVjdCA9IHRuX3NldXJhdCkKYGBgCgpUbyBmaW5kIERFIGdlbmVzIGJldHdlZW4gYnVsa2l6ZWQgVE4gc2FtcGxlcyB3aXRoIGxvdyBhbmQgaGlnaCBET1IsIGV4cG9ydCB0YWJsZSB3aXRoIGdyb3VwcwpgYGB7cn0KIyBzZXQgdXAgdGFibGUgCnNhbXBsZS5hdmVyYWdlcy50IDwtIGFzLmRhdGEuZnJhbWUodChzYW1wbGUuYXZlcmFnZXMpKQpoZWFkKHNhbXBsZS5hdmVyYWdlcy50KQpzYW1wbGUuYXZlcmFnZXMudCRzYW1wbGVfbmFtZSA8LSByb3duYW1lcyhzYW1wbGUuYXZlcmFnZXMudCkKc2FtcGxlLmF2ZXJhZ2VzLnQgPC0gbGVmdF9qb2luKHNhbXBsZS5hdmVyYWdlcy50LCBkb3JfbWV0YSwgYnkgPSAic2FtcGxlX25hbWUiKQpyb3duYW1lcyhzYW1wbGUuYXZlcmFnZXMudCkgPC0gc2FtcGxlLmF2ZXJhZ2VzLnQkc2FtcGxlX25hbWUKCmxlbmd0aChjb2xuYW1lcyhzYW1wbGUuYXZlcmFnZXMudCkpCkRFX2F2ZyA8LSBwYWlyd2lzZS53aWxjb3gudGVzdCh4ID0gc2FtcGxlLmF2ZXJhZ2VzLnQkRUdGUiwgZyA9IHNhbXBsZS5hdmVyYWdlcy50JGRvcl9jbGFzcykKd3JpdGUuY3N2KHNhbXBsZS5hdmVyYWdlcy50LCBmaWxlID0gIi9teVZvbHVtZS9UTl9idWxraXplZF9kYXRhLmNzdiIpClROLnNhbXBsZS5hdmVyYWdlcyA8LSBzYW1wbGUuYXZlcmFnZXMKaGVhZChUTi5zYW1wbGUuYXZlcmFnZXMpCmBgYAoKCkJ1bGtpemUgZml0IGFuYWx5c2lzIEFsdmVvbGFyCmBgYHtyfQpBbHZlb2xhcl9zaWcgPC0gYygiU0ZUUEMiLCAiU0ZUUEIiLCAiU0ZUUEQiLCAiUEdDIiwgIkNMRE4xOCIsICJBUVA0IiwgIlNDR0IzQTEiLCAiQUJDQTMiLCAiR0FUQTYiLCAiTktYMi0xIiwgIlNGVEEzIiwgIklHRkJQMiIsICJIT1BYIiwgIk5BUFNBIiwgIkZPWEEyIiwgIkFHRVIiLCAiTEFNUDEiKQpUTl9BbHZlb2xhciA8LSBUTi5zYW1wbGUuYXZlcmFnZXNbQWx2ZW9sYXJfc2lnLCBdClROX0FsdmVvbGFyX21lYW4gPC0gYXMuZGF0YS5mcmFtZShjb2xNZWFucyhUTl9BbHZlb2xhcikpClROX0FsdmVvbGFyX21lYW4kc2FtcGxlX25hbWUgPC0gcm93bmFtZXMoVE5fQWx2ZW9sYXJfbWVhbikKVE5fQWx2ZW9sYXJfbWVhbiA8LSBsZWZ0X2pvaW4oVE5fQWx2ZW9sYXJfbWVhbiwgZG9yX21ldGEsIGJ5ID0gInNhbXBsZV9uYW1lIikKcm93bmFtZXMoVE5fQWx2ZW9sYXJfbWVhbikgPC0gVE5fQWx2ZW9sYXJfbWVhbiRzYW1wbGVfbmFtZQoKVE5fQWx2ZW9sYXJfZml0IDwtIGxtKGRvciB+IGNvbE1lYW5zKFROX0FsdmVvbGFyKSwgZGF0YT0gVE5fQWx2ZW9sYXJfbWVhbikKc3VtbWFyeShUTl9BbHZlb2xhcl9maXQpClROX0FsdmVvbGFyX21lYW4kcHJlZGxtIDwtIHByZWRpY3QoVE5fQWx2ZW9sYXJfZml0KQoKZ2dwX1ROX0FsdmVvbGFyIDwtIGdncGxvdChUTl9BbHZlb2xhcl9tZWFuLCBhZXMoeCA9IGNvbE1lYW5zKFROX0FsdmVvbGFyKSwgeSA9IGRvciwgY29sb3IgPSBkb3JfY2xhc3MpKSArIGdlb21fcG9pbnQoKQoKZ2dzYXZlKGdncF9UTl9BbHZlb2xhciwgZmlsZW5hbWUgPSBwYXN0ZShkaXIsICJwbG90X291dC9OSTA4L1ROX0FsdmVvbGFyX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgpCdWxraXplIGZpdCBhbmFseXNpcyBLeW51cmVuaW5lCmBgYHtyfQpLeW51cmVuaW5lX3NpZyA8LSBjKCdJRE8xJywgJ0tZTlUnLCAnUVBSVCcpClROX0t5bnVyZW5pbmUgPC0gVE4uc2FtcGxlLmF2ZXJhZ2VzW0t5bnVyZW5pbmVfc2lnLCBdClROX0t5bnVyZW5pbmVfbWVhbiA8LSBhcy5kYXRhLmZyYW1lKGNvbE1lYW5zKFROX0t5bnVyZW5pbmUpKQpUTl9LeW51cmVuaW5lX21lYW4kc2FtcGxlX25hbWUgPC0gcm93bmFtZXMoVE5fS3ludXJlbmluZV9tZWFuKQpUTl9LeW51cmVuaW5lX21lYW4gPC0gbGVmdF9qb2luKFROX0t5bnVyZW5pbmVfbWVhbiwgZG9yX21ldGEsIGJ5ID0gInNhbXBsZV9uYW1lIikKcm93bmFtZXMoVE5fS3ludXJlbmluZV9tZWFuKSA8LSBUTl9LeW51cmVuaW5lX21lYW4kc2FtcGxlX25hbWUKClROX0t5bnVyZW5pbmVfZml0IDwtIGxtKGRvciB+IGNvbE1lYW5zKFROX0t5bnVyZW5pbmUpLCBkYXRhPSBUTl9LeW51cmVuaW5lX21lYW4pCnN1bW1hcnkoVE5fS3ludXJlbmluZV9maXQpCgpnZ3BfVE5fS3ludXJlbmluZSA8LSBnZ3Bsb3QoVE5fS3ludXJlbmluZV9tZWFuLCBhZXMoeCA9IGNvbE1lYW5zKFROX0t5bnVyZW5pbmUpLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvcj1kb3JfY2xhc3MpKQpnZ3NhdmUoZ2dwX1ROX0t5bnVyZW5pbmUsIGZpbGVuYW1lID0gcGFzdGUoZGlyLCAicGxvdF9vdXQvTkkwOC9UTl9LeW51cmVuaW5lX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgpCdWxraXplIGZpdCBhbmFseXNpcyBQbGFzbWlub2dlbgpgYGB7cn0KUGxhc21pbm9nZW5fc2lnIDwtIGMoJ0FOWEEyJywgJ1BMQVQnLCAnUExBVScsICdQTEFVUicpClROX1BsYXNtaW5vZ2VuIDwtIFROLnNhbXBsZS5hdmVyYWdlc1tQbGFzbWlub2dlbl9zaWcsIF0KVE5fUGxhc21pbm9nZW5fbWVhbiA8LSBhcy5kYXRhLmZyYW1lKGNvbE1lYW5zKFROX1BsYXNtaW5vZ2VuKSkKVE5fUGxhc21pbm9nZW5fbWVhbiRzYW1wbGVfbmFtZSA8LSByb3duYW1lcyhUTl9QbGFzbWlub2dlbl9tZWFuKQpUTl9QbGFzbWlub2dlbl9tZWFuIDwtIGxlZnRfam9pbihUTl9QbGFzbWlub2dlbl9tZWFuLCBkb3JfbWV0YSwgYnkgPSAic2FtcGxlX25hbWUiKQpyb3duYW1lcyhUTl9QbGFzbWlub2dlbl9tZWFuKSA8LSBUTl9QbGFzbWlub2dlbl9tZWFuJHNhbXBsZV9uYW1lCgpUTl9QbGFzbWlub2dlbl9maXQgPC0gbG0oZG9yIH4gY29sTWVhbnMoVE5fUGxhc21pbm9nZW4pLCBkYXRhPSBUTl9QbGFzbWlub2dlbl9tZWFuKQpzdW1tYXJ5KFROX1BsYXNtaW5vZ2VuX2ZpdCkKCmdncF9UTl9QbGFzbWlub2dlbiA8LSBnZ3Bsb3QoVE5fUGxhc21pbm9nZW5fbWVhbiwgYWVzKHggPSBjb2xNZWFucyhUTl9QbGFzbWlub2dlbiksIHkgPSBkb3IpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZG9yX2NsYXNzKSkKZ2dzYXZlKGdncF9UTl9QbGFzbWlub2dlbiwgZmlsZW5hbWUgPSBwYXN0ZShkaXIsICJwbG90X291dC9OSTA4L1ROX1BsYXNtaW5vZ2VuX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgpCdWxraXplIGZpdCBhbmFseXNpcyBvZiBTRVJQSU5FMQpgYGB7cn0KVE5fU2VycGluZV9zaWcgPC0gIGFzLmRhdGEuZnJhbWUodChUTi5zYW1wbGUuYXZlcmFnZXNbIlNFUlBJTkUxIiwgXSkpClROX1NlcnBpbmVfc2lnJHNhbXBsZV9uYW1lIDwtIHJvd25hbWVzKFROX1NlcnBpbmVfc2lnKQpUTl9TZXJwaW5lX3NpZyA8LSBsZWZ0X2pvaW4oVE5fU2VycGluZV9zaWcsIGRvcl9tZXRhLCBieSA9ICJzYW1wbGVfbmFtZSIpCnJvd25hbWVzKFROX1NlcnBpbmVfc2lnKSA8LSBUTl9TZXJwaW5lX3NpZyRzYW1wbGVfbmFtZQoKVE5fU2VycGluZV9maXQgPC0gbG0oZG9yIH4gU0VSUElORTEsIGRhdGE9IFROX1NlcnBpbmVfc2lnKQpzdW1tYXJ5KFROX1NlcnBpbmVfZml0KQoKZ2dwX1ROX1NlcnBpbmUxIDwtIGdncGxvdChUTl9TZXJwaW5lX3NpZywgYWVzKHggPSBTRVJQSU5FMSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3NhdmUoZ2dwX1ROX1NlcnBpbmUxLCBmaWxlbmFtZSA9IHBhc3RlKGRpciwgInBsb3Rfb3V0L05JMDgvVE5fU2VycGluZTFfYnVsa2l6ZWQucGRmIiwgc2VwID0gIiIpKQpgYGAKCkJ1bGtpemUgZml0IGFuYWx5c2lzIEdhcEp1bmN0aW9uCmBgYHtyfQpHYXBKdW5jdGlvbl9zaWcgPC0gYygnR0pCMycsICdHSkIyJywgJ0dKQjQnLCdHSkI1JykKVE5fR2FwSnVuY3Rpb24gPC0gVE4uc2FtcGxlLmF2ZXJhZ2VzW0dhcEp1bmN0aW9uX3NpZywgXQpUTl9HYXBKdW5jdGlvbl9tZWFuIDwtIGFzLmRhdGEuZnJhbWUoY29sTWVhbnMoVE5fR2FwSnVuY3Rpb24pKQpUTl9HYXBKdW5jdGlvbl9tZWFuJHNhbXBsZV9uYW1lIDwtIHJvd25hbWVzKFROX0dhcEp1bmN0aW9uX21lYW4pClROX0dhcEp1bmN0aW9uX21lYW4gPC0gbGVmdF9qb2luKFROX0dhcEp1bmN0aW9uX21lYW4sIGRvcl9tZXRhLCBieSA9ICJzYW1wbGVfbmFtZSIpCnJvd25hbWVzKFROX0dhcEp1bmN0aW9uX21lYW4pIDwtIFROX0dhcEp1bmN0aW9uX21lYW4kc2FtcGxlX25hbWUKClROX0dhcEp1bmN0aW9uX2ZpdCA8LSBsbShkb3IgfiBjb2xNZWFucyhUTl9HYXBKdW5jdGlvbiksIGRhdGE9IFROX0dhcEp1bmN0aW9uX21lYW4pCnN1bW1hcnkoVE5fR2FwSnVuY3Rpb25fZml0KQoKZ2dwX1ROX0dhcEp1bmN0aW9uIDwtIGdncGxvdChUTl9HYXBKdW5jdGlvbl9tZWFuLCBhZXMoeCA9IGNvbE1lYW5zKFROX0dhcEp1bmN0aW9uKSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3NhdmUoZ2dwX1ROX0dhcEp1bmN0aW9uLCBmaWxlbmFtZSA9IHBhc3RlKGRpciwgInBsb3Rfb3V0L05JMDgvVE5fR2FwSnVjaW9uX2J1bGtpemVkLnBkZiIsIHNlcCA9ICIiKSkKYGBgCgoKYGBge3J9CmJ1bGtpemVkX1ROX21hcmtlcnMgPC0gcmVhZC5jc3YoZmlsZSA9IHBhc3RlKGRpciwgIkRhdGFfaW5wdXQvbXd1X2x1YWQuY3N2Iiwgc2VwID0gIiIpKQpidWxraXplZF9UTl9tYXJrZXJzLmYgPC0gZmlsdGVyKGJ1bGtpemVkX1ROX21hcmtlcnMsIHB2YWxfMSA8PSAwLjA1KQpoaXN0KGJ1bGtpemVkX1ROX21hcmtlcnMuZiRzdGF0XzEpCmxlbmd0aChidWxraXplZF9UTl9tYXJrZXJzLmYkcHZhbF8xKQpidWxraXplZF9UTl9tYXJrZXJzLmYgPC0gYnVsa2l6ZWRfVE5fbWFya2Vycy5mW29yZGVyKGJ1bGtpemVkX1ROX21hcmtlcnMuZiRzdGF0XzEsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXSAKYGBgCgpgYGB7cn0KdGFibGUoYnVsa2l6ZWRfVE5fbWFya2Vycy5mJHRlc3QpCmBgYAoKTW9zdCBjb21wZWxsaW5nIGhpZ2ggZXhwcmVzc2lvbiBjb3JyIHRvIGxvdyBkb3IKYGBge3J9CmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBBREFSLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBhdGllbnRfaWQpKQpnZ3Bsb3Qoc2FtcGxlLmF2ZXJhZ2VzLnQsIGFlcyh4ID0gQ0ZMMSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwYXRpZW50X2lkKSkKYGBgCgpNb3N0IGNvbXBlbGxpbmcgaGlnaCBleHByZXNzaW9uIGNvcnIgdG8gaGlnaCBkb3IKYGBge3J9CmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBUVExMMTNQLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBBTFMyLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBSTE4xLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBVU1A0NSwgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3Bsb3Qoc2FtcGxlLmF2ZXJhZ2VzLnQsIGFlcyh4ID0gQkRLUkIxLCB5ID0gZG9yKSkgKyBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGRvcl9jbGFzcykpCmdncGxvdChzYW1wbGUuYXZlcmFnZXMudCwgYWVzKHggPSBMSU5DMDEwNjEsIHkgPSBkb3IpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZG9yX2NsYXNzKSkKZ2dwbG90KHNhbXBsZS5hdmVyYWdlcy50LCBhZXMoeCA9IFpORjU2MywgeSA9IGRvcikpICsgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkb3JfY2xhc3MpKQpnZ3Bsb3Qoc2FtcGxlLmF2ZXJhZ2VzLnQsIGFlcyh4ID0gV0RSMTksIHkgPSBkb3IpKSArIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZG9yX2NsYXNzKSkKYGBgCgo=